package com.suray.basic.wcs.plc.pojo;

import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.core.PlcOffset;
import com.suray.basic.wcs.plc.enums.Network;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.CarMap;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.LifterMap;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.PalletMap;
import com.suray.basic.wcs.plc.service.impl.PlcDeviceDBServiceImpl;
import com.suray.basic.wcs.plc.utils.NetAddress;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.basic.wcs.plc.utils.PalletStatus;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author shaozn
 * @date 2020/2/12 - 15:08
 * @Description 设备基类
 */
public class DeviceBase {

    protected Map<Integer, LifterMap> lifterLayerMap = new HashMap<>();

    protected Map<Coord, CarMap> carLocationMap = new HashMap<>();

    protected Map<PalletStatus, PalletMap> palletStatusMap = new HashMap<>();

    private static final PlcDeviceDBServiceImpl plcDeviceDBService = SpringContextHolder.getBean(PlcDeviceDBServiceImpl.class);

    private int plcId;

    private String series;

    public void setSeries(String series) {
        this.series = series;
    }

    public String getSeries() {
        return series;
    }

    public DeviceBase(PlcDeviceType plcDeviceType, int startNo, String deviceName, int deviceNo, Coord coord, Location location, Coord lockLocation,
                      long deviceId, Integer gridzMax, Integer gridzRelative, int plcId) {
        this.plcDeviceType = plcDeviceType;
        this.startNo = startNo;
        this.deviceName = deviceName;
        this.deviceNo = deviceNo;
        this.coord = coord;
        this.location = location;
        this.lockLocation = lockLocation;
        this.deviceId = deviceId;
        this.gridzMax = gridzMax;
        this.gridzRelative = gridzRelative;
        this.plcId = plcId;
        this.series = String.valueOf(plcId);
    }

    /**
     * 货叉提升机的基本数据
     * 加载货叉提升机的时候需要填充
     *
     * @param lifterLayerMap
     * @param carLocationMap
     * @param palletStatusMap
     */
    public void analyzeLifterInfoDis(Map<Integer, LifterMap> lifterLayerMap, Map<Coord, CarMap> carLocationMap,
                                      Map<PalletStatus, PalletMap> palletStatusMap) {
        this.lifterLayerMap = lifterLayerMap;
        this.carLocationMap = carLocationMap;
        this.palletStatusMap = palletStatusMap;
    }

    /**
     * 设备id
     */
    private long deviceId;

    private Coord lockCoord;

    /**
     * 所属PLC
     */
    private Plc plc;
    /**
     * PLC设备类型
     */
    private PlcDeviceType plcDeviceType;
    /**
     * 起始地址
     */
    private int startNo;
    /**
     * 设备名字
     */
    private String deviceName;
    /**
     * 设备编号
     */
    private int deviceNo;
    /**
     * 设备坐标
     */
    private Coord coord;
    /**
     * 提升机左右
     */
    private Location location;
    /**
     * 锁定位置
     */
    private Coord lockLocation;

    /**
     * 提升机最大层数
     */
    private Integer gridzMax;

    /**
     * 提升机相对于货架的层数
     */
    private Integer gridzRelative;
    /**
     * 网络信息
     */
    private NetAddress netAddress;

    private String status;

    public int getPlcId() {
        return plcId;
    }

    public String getStatus() {
        return status;
    }

    public void setDeviceStatus(String des) {
        status = des;
    }

    public String getDeviceStatus() {
        return status;
    }

    public NetAddress getNetAddress() {
        return netAddress;
    }

    public void setNetAddress(NetAddress netAddress) {
        this.netAddress = netAddress;
    }

    public void clearDeviceTask() {
        plcDeviceDBService.clearDeviceTask(deviceId);
    }

    public Coord getLockLocation() {
        return lockLocation;
    }

    public void setLockLocation(Coord lockLocation) {
        this.lockLocation = lockLocation;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

    public int getDeviceNo() {
        return deviceNo;
    }

    public void setDeviceNo(int deviceNo) {
        this.deviceNo = deviceNo;
    }

    public Coord getCoord() {
        return coord;
    }

    public void setCoord(Coord coord) {
        this.coord = coord;
    }

    public Plc getPlc() {
        return plc;
    }

    public void setPlc(Plc plc) {
        this.plc = plc;
    }

    public int getStartNo() {
        return startNo;
    }

    public void setStartNo(int startNo) {
        this.startNo = startNo;
    }

    public PlcDeviceType getPlcDeviceType() {
        return plcDeviceType;
    }

    public void setPlcDeviceType(PlcDeviceType plcDeviceType) {
        this.plcDeviceType = plcDeviceType;
    }

    public long getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(long deviceId) {
        this.deviceId = deviceId;
    }

    public Coord getLockCoord() {
        return lockCoord;
    }

    public void setLockCoord(Coord lockCoord) {
        this.lockCoord = lockCoord;
    }

    public Integer getGridzMax() {
        return gridzMax;
    }

    public void setGridzMax(Integer gridzMax) {
        this.gridzMax = gridzMax;
    }

    public Integer getGridzRelative() {
        return gridzRelative;
    }

    public void setGridzRelative(Integer gridzRelative) {
        this.gridzRelative = gridzRelative;
    }

    public Map<Integer, LifterMap> getLifterLayerMap() {
        return lifterLayerMap;
    }

    public void setLifterLayerMap(Map<Integer, LifterMap> lifterLayerMap) {
        this.lifterLayerMap = lifterLayerMap;
    }

    public Map<Coord, CarMap> getCarLocationMap() {
        return carLocationMap;
    }

    public void setCarLocationMap(Map<Coord, CarMap> carLocationMap) {
        this.carLocationMap = carLocationMap;
    }

    public LifterMap getLifterLocationInfoByLifterDis(int distance) {
        for (LifterMap lifterMap : lifterLayerMap.values()) {
            if (lifterMap.distance == distance) {
                return lifterMap;
            }
        }

        throw new RuntimeException("错误的提升机位移，找不到对应的数据");
    }

    public Map<PalletStatus, PalletMap> getPalletStatusMap() {
        return palletStatusMap;
    }

    public void setPalletStatusMap(Map<PalletStatus, PalletMap> palletStatusMap) {
        this.palletStatusMap = palletStatusMap;
    }

    /**
     * 从指定地址获取信息(从查询结果数组中读取)
     *
     * @param plcOffset 点位偏移量对象
     * @return
     */
    protected int readPlc(PlcOffset plcOffset) {
        try {
            if (plc.getPlcStatus() == Network.OFF_LINE) {
                return 0;
            }

            if (plcOffset.getBitOffset() == null) {
                return plc.getPlcCache().getPlcStatus()[this.startNo + plcOffset.getAddressOffset() - plc.getPlcParam().getStartNum()];
            } else {
                return 1 & (plc.getPlcCache().getPlcStatus()[this.startNo + plcOffset.getAddressOffset() - plc.getPlcParam().getStartNum()] >> plcOffset.getBitOffset());
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            LoggerUtil.info("startNo:" + this.startNo + ", AddressOffset:" + plcOffset.getAddressOffset()
                    + "StartNum:" + plc.getPlcParam().getStartNum(), this.getClass());
            e.printStackTrace();

            return 0;
        }
    }

    /**
     * 获取条码数据
     *
     * @param no
     * @param bit
     * @return
     */
    protected int getBarCodeByBit(int no, int bit) {
        return (plc.getPlcCache().getPlcStatus()[this.startNo + no - plc.getPlcParam().getStartNum()] >> bit) & 0xff;
    }

    public String getPlcStatusStr() {
        return WcsFuncUtil.arrayToHexString(plc.getPlcCache().getPlcStatus());
    }


    /**
     * 向指定地址写入指定字
     *
     * @param no
     * @param oper_sign
     */
    protected void oper(String des, Class<?> clazz, int no, int resendCount, int oper_sign) throws IOException {
        plc.getModbusUtil().oper(des, clazz, this.startNo + no, resendCount, oper_sign);
    }

    /**
     * 向指定地址写入指定数组
     *
     * @param no
     * @param oper_sign
     */
    protected void oper(String des, Class<?> clazz, int no, int resendCount, int[] oper_sign) throws IOException {
        plc.getModbusUtil().oper(des, clazz, this.startNo + no, resendCount, oper_sign);
    }

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

    @Override
    public String toString() {
        return super.toString();
    }

}
